using System;
using System.Collections.Generic;
using System.Text;
using BizTalkCop.Rules.Bases;
using Microsoft.FxCop.Sdk;
using BizTalkCop.Rules.Enums;
using System.Xml.XPath;
using System.Xml;

namespace BizTalkCop.Rules.Naming.Rules
{
    /// <summary>
    /// Rule verifying orchestration types are Pascal cased
    /// </summary>
    /// <remarks>
    /// Checks type names for: correlation types, multi-part message types, multi-part message parts, 
    /// port types and role link types
    /// </remarks>
    public class OrchestrationTypesShouldBePascalCased : OrchestrationRuleBase
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public OrchestrationTypesShouldBePascalCased() : base("OrchestrationTypesShouldBePascalCased") { }

        private static Dictionary<OMElementType, string> _types;
        private static Dictionary<OMElementType, string> Types
        {
            get
            {
                if (_types == null)
                {
                    _types = new Dictionary<OMElementType, string>();
                    _types.Add(OMElementType.CorrelationType, "Correlation Type");
                    _types.Add(OMElementType.MultipartMessageType, "Multi-Part Message Type");
                    _types.Add(OMElementType.PartDeclaration, "Multi-Part Message Part");
                    _types.Add(OMElementType.PortType, "Port Type");
                    _types.Add(OMElementType.ServiceLinkType, "Role Link Type");
                }
                return _types;
            }
        }

        /// <summary>
        /// Checks if the orchestration's types are Pascal cased
        /// </summary>
        /// <param name="type">Type to check</param>
        /// <returns>Problem collection</returns>
        public override ProblemCollection Check(TypeNode type)
        {
            if (IsOrchestration(type))
            {
                foreach (KeyValuePair<OMElementType, string> elementType in Types)
                {
                    XPathNodeIterator elements = GetOMElements(type, elementType.Key);
                    this.CheckElements(elements, elementType.Value, type);
                }
            }
            return Problems;
        }

        private void CheckElements(XPathNodeIterator elements, string elementTypeName, TypeNode type)
        {
            foreach (XPathNavigator navigator in elements)
            {
                string name = SelectSingleNode(navigator, XPathQuery.OMNamePropertyNode).Value;
                if (!MemberName.IsPascalCase(name))
                {
                    Problems.Add(new Problem(GetNamedResolution("Case", elementTypeName, name, MemberName.ToPascalCase(name)), type));
                }
            }            
        }
    }
}
